#ifndef __JPEG_H
#define __JPEG_H

#include "stm32h7xx_hal.h"
#include "fatfs.h"

class HWJpegDecoder
{

public:
    enum Error
    {
        NoError = 0,
        DeviceBusy,
        NoInputData,
        FileNoExist,
        InputOutOfMemory,
        InvalidImage,
        OutputOutOfMemory,
        HWError,
        NoData,
    };

    struct ImageInfo
    {
        uint32_t height;            // 图片高度
        uint32_t width;             // 图片宽度
        uint32_t chromaSubsampling; // 图片颜色格式
        uint8_t MCUWidth;           // 图片最小单元(MCU)宽度
		uint8_t MCUHeight;          // 图片最小单元(MCU)高度
        uint32_t MCUSize;           // 图片最小单元所占字节数

        uint32_t MCUPerLine;        // 图片一行最小单元(MCU)个数
        uint32_t MCULines;          // 图片最小单元(MCU)行数
    };

    // 参数: 图片信息, 图像解码数据块, 数据块行索引, 数据块行数
    using OutputCb = void (*)(ImageInfo &info, const void *data, uint32_t line, uint32_t numOfLine);

private:
    static constexpr uint32_t fullInputSize = 64 * 1024;        // 全尺寸输入时，每次解码的数据量(受限于MDMA buffer传输64KB)
    static constexpr uint32_t fullOutputSize = 64 * 1024;       // 全尺寸输出时，每次解码输出的数据量(受限于MDMA buffer传输64KB)

    static constexpr uint32_t defaultInputBufferSize = 16 * 1024;       // 非全尺寸输入时，每次读取&解码的数据量
    static constexpr uint32_t defaultOutputBufferSize = 32 * 1024;      // 非全尺寸输出时，用于解码输出的缓冲区

    volatile bool deviceBusyFlag = false; // 设备忙? 

    QueueHandle_t jpegQueue = nullptr;            // 消息队列 
    enum JpegMsg
    {
        DecodeInit = 0,
        DecodeGetData,
        DecodeDataReady,
        DecodeCplt,
        JpegError,
        JpegReset,        
    };

    SemaphoreHandle_t decodeCpltSem;    // 解码完成信号量

    uint32_t frameBufferAddress = 0; // JPEG解码后数据地址
    uint32_t JPEGSourceAddress = 0;  // JPEG数据源地址
    uint32_t inputFrameSize = 0;     // JPEG源数据大小
    uint32_t inputFrameIndex = 0;    // JPEG解码过程中，已经解码的数据大小
    uint32_t outputFrameSize = 0;    // JPEG解码输出缓冲区大小
    uint32_t outputFrameLineIndex = 0;  // JPEG解码过程中，已经解码的MCU行数
    uint32_t outputFrameLines = 0;   // JPEG解码过程中，单次解码输出MCU行数

    JPEG_HandleTypeDef *hwHandle; // jpeg硬件对象

    const uint8_t *inputData = nullptr; // jpeg输入数据
    uint32_t inputDataSize = 0;         // jpeg输入数据长度

    const char *inputFilePath = nullptr; // jpeg输入文件路径
    FIL *inputFile = nullptr;            // jpeg文件对象

    uint8_t *inputBuffer = nullptr;     // jpeg输入数据缓冲区
    uint32_t inputBufferSize = 0;

    uint8_t *outputBuffer = nullptr; // jpeg输出数据缓冲区

    uint16_t outputMCULine = 0;     // 非全尺寸图片输出时，单次输出的MCU行数

    OutputCb outputCallback = nullptr;  // 非全尺寸图片输出时，读取输出数据的回调函数

    ImageInfo info; // 图片信息

    bool fullInput = false;     // 全尺寸图片输入(一次读取整个文件)
    bool fullOutput = false;    // 全尺寸图片输出(一次输出整张图片)

    friend void JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData);
    friend void JPEG_DataReadyCallback(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength);
    friend void JPEG_ErrorCallback(JPEG_HandleTypeDef *hjpeg);
    friend void JPEG_DecodeCpltCallback(JPEG_HandleTypeDef *hjpeg);

    friend void HWJpegDecoderThread(void *arg);

    void JPEG_GetDataProcess(void);
    void JPEG_DataReadyProcess(void);
    void JPEG_DecodeCpltProcess(void);
    void JPEG_ErrorProcess(void);

    int decodeHeader(void);

public:
    HWJpegDecoder(JPEG_HandleTypeDef *hwJpegHandler = nullptr);
    ~HWJpegDecoder();

    ImageInfo &getImageInfo(void);

    void setInputDataSource(const uint8_t *data, uint32_t size);
    void setInputDataSource(const char *path);

    void setFullInput(bool en);
    void setFullOutput(bool en);

    void setOutputCallback(OutputCb outputCb);

    Error decode(bool onlyHeader = false);
    bool isDecodeFinish(void) { return !deviceBusyFlag; }
    void waitDecodeFinish(void);

    uint8_t *getImage(void);

    void reset(void);
};

#endif
